/*
 * Binary.cpp
 *
 *  Created on: 29.04.2012
 *      Author: Eugene Kornykhin
 */

#include "Operation.h"
#include "Number.h"
#include "BooleanConst.h"
#include <stdexcept>
#include <typeinfo>

void Addition::push_operation_result(Interpreter &interpreter, const PElement &_x, const PElement &_y)
{
	try {
		const Number &x = dynamic_cast<const Number &>(_x);
		const Number &y = dynamic_cast<const Number &>(_y);
		interpreter.pushPolizElement(Number(x.getValue() + y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}
void Subtraction::push_operation_result(Interpreter &interpreter, const PElement &_x, const PElement &_y)
{
	try {
		const Number &x = dynamic_cast<const Number &>(_x);
		const Number &y = dynamic_cast<const Number &>(_y);
		interpreter.pushPolizElement(Number(x.getValue() - y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}
void Equality::push_operation_result(Interpreter &interpreter, const PElement &_x, const PElement &_y)
{
	try {
		const Number &x = dynamic_cast<const Number &>(_x);
		const Number &y = dynamic_cast<const Number &>(_y);
		interpreter.pushPolizElement(BooleanConst(x.getValue() == y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}
void NotEquality::push_operation_result(Interpreter &interpreter, const PElement &_x, const PElement &_y)
{
	try {
		const Number &x = dynamic_cast<const Number &>(_x);
		const Number &y = dynamic_cast<const Number &>(_y);
		interpreter.pushPolizElement(BooleanConst(x.getValue() != y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}
void Less::push_operation_result(Interpreter &interpreter, const PElement &_x, const PElement &_y)
{
	try {
		const Number &x = dynamic_cast<const Number &>(_x);
		const Number &y = dynamic_cast<const Number &>(_y);
		interpreter.pushPolizElement(BooleanConst(x.getValue() < y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}
void NotLess::push_operation_result(Interpreter &interpreter, const PElement &_x, const PElement &_y)
{
	try {
		const Number &x = dynamic_cast<const Number &>(_x);
		const Number &y = dynamic_cast<const Number &>(_y);
		interpreter.pushPolizElement(BooleanConst(x.getValue() >= y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}

Binary *Addition::clone(const Poliz &) const
{
	return new Addition();
}

string Addition::toString() const
{
	return "+";
}

Binary *Subtraction::clone(const Poliz &) const
{
	return new Subtraction();
}
string Subtraction::toString() const
{
	return "-";
}


Binary *Equality::clone(const Poliz &) const
{
	return new Equality();
}
string Equality::toString() const
{
	return "=";
}


Binary *NotEquality::clone(const Poliz &) const
{
	return new NotEquality();
}
string NotEquality::toString() const
{
	return "!=";
}


Binary *Less::clone(const Poliz &) const
{
	return new Less();
}
string Less::toString() const
{
	return "<";
}


Binary *NotLess::clone(const Poliz &) const
{
	return new NotLess();
}
string NotLess::toString() const
{
	return ">=";
}

void Greater::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const Number &x = dynamic_cast<const Number &>(left);
		const Number &y = dynamic_cast<const Number &>(right);
		interpreter.pushPolizElement(BooleanConst(x.getValue() > y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}

Binary* Greater::clone(const Poliz& poliz) const {
	return new Greater();
}

string Greater::toString() const {
	return ">";
}

void LessOrEq::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const Number &x = dynamic_cast<const Number &>(left);
		const Number &y = dynamic_cast<const Number &>(right);
		interpreter.pushPolizElement(BooleanConst(x.getValue() <= y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}

Binary* LessOrEq::clone(const Poliz& poliz) const {
	return new LessOrEq();
}

string LessOrEq::toString() const {
	return "<=" ;
}

void Multiplication::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const Number &x = dynamic_cast<const Number &>(left);
		const Number &y = dynamic_cast<const Number &>(right);
		interpreter.pushPolizElement(Number(x.getValue() * y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}

Binary* Multiplication::clone(const Poliz& poliz) const {
	return new Multiplication();
}

string Multiplication::toString() const {
	return "*";
}

void Division::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const Number &x = dynamic_cast<const Number &>(left);
		const Number &y = dynamic_cast<const Number &>(right);
		interpreter.pushPolizElement(Number(x.getValue() / y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}

Binary* Division::clone(const Poliz& poliz) const {
	return new Division();
}

string Division::toString() const {
	return "div" ;
}

void Modulo::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const Number &x = dynamic_cast<const Number &>(left);
		const Number &y = dynamic_cast<const Number &>(right);
		interpreter.pushPolizElement(Number(x.getValue() % y.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 numbers as arguments");
	}
}

Binary* Modulo::clone(const Poliz& poliz) const {
	return new Modulo();
}

string Modulo::toString() const {
	return "mod";
}

void Conjunction::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const BooleanConst &x = dynamic_cast<const BooleanConst &>(left);
		const BooleanConst &y = dynamic_cast<const BooleanConst &>(right);
		interpreter.pushPolizElement(BooleanConst(x.isTrue() && y.isTrue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 booleans as arguments");
	}

}

Binary* Conjunction::clone(const Poliz& poliz) const {
	return new Conjunction();
}

string Conjunction::toString() const {
	return "and";
}

void Disjunction::push_operation_result(Interpreter& interpreter,
		const PElement& left, const PElement& right) {
	try {
		const BooleanConst &x = dynamic_cast<const BooleanConst &>(left);
		const BooleanConst &y = dynamic_cast<const BooleanConst &>(right);
		interpreter.pushPolizElement(BooleanConst(x.isTrue() || y.isTrue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires 2 booleans as arguments");
	}
}

Binary* Disjunction::clone(const Poliz& poliz) const {
	return new Disjunction();
}

string Disjunction::toString() const {
	return "or";
}

void Negation::push_operation_result(Interpreter& interpreter,
		const PElement& arg) {
	try {
		const Number &x = dynamic_cast<const Number &>(arg);
		interpreter.pushPolizElement(Number(- x.getValue()));
	} catch(bad_cast&) {
		throw std::logic_error("Operation `" + toString() + "' requires a number as an argument");
	}
}

Unary* Negation::clone(const Poliz& poliz) const {
	return new Negation();
}

string Negation::toString() const {
	return "- (unary)";
}


